/* voom.c
** 
** Copyright (c) 2007, Homebrew Mobile Phone Club
** All rights reserved.
** 
** Redistribution  and  use  in  source  and  binary  forms,  with  or  without
** modification, are permitted provided that the following conditions are met:
** 
**  * Redistributions of  source code must  retain the above  copyright notice,
**    this list of conditions and the following disclaimer.
** 
**  * Redistributions in binary form must reproduce the above copyright notice,
**    this list of conditions and the following disclaimer in the documentation
**    and/or other materials provided with the distribution.
** 
**  * Neither the name  of the Homebrew Mobile Phone Club nor  the names of its
**    contributors may be used to endorse or promote products derived from this
**    software without specific prior written permission.
** 
** THIS SOFTWARE IS PROVIDED BY  THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY  EXPRESS OR IMPLIED WARRANTIES,  INCLUDING, BUT NOT  LIMITED TO, THE
** IMPLIED WARRANTIES  OF MERCHANTABILITY AND FITNESS FOR  A PARTICULAR PURPOSE
** ARE DISCLAIMED.  IN NO  EVENT SHALL THE  COPYRIGHT OWNER OR  CONTRIBUTORS BE
** LIABLE  FOR  ANY  DIRECT,   INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
** CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT  LIMITED  TO,  PROCUREMENT  OF
** SUBSTITUTE GOODS  OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
** INTERRUPTION)  HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN
** CONTRACT,  STRICT LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE OR  OTHERWISE)
** ARISING IN ANY WAY  OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
** 
** $Id: voom.c 10 2007-11-07 21:06:20Z msh.mobile $
*/

/* Macro Definitions */
#define VOOM_KERNEL

/* File Includes */
#include "voom.h"

/* Typedefs, Structs, Unions, Enums, etc. */
typedef union {
  uint32_t t_word;
  uint8_t t_array[sizeof(uint32_t)];
} tWordTest;

/* Static Function Prototypes */
static void voom_usage( tVoomApp *app );
static void voom_file( void );

/* Variable Declarations */

/* Function Definitions */

tVoomErr voom_init( tVoomApp **app, int argc, char **argv ) {
  VOOM_ENTER;
  uint32_t allocated = 0;
  tWordTest word_test;

  VOOM_BEGIN {
    VOOM_NULLCHECK(app,tVoomApp**);

    /* If *app is NULL, it means we want to allocate a new one. */
    if( (tVoomApp *) NULL == *app ) {
      *app = (tVoomApp *) malloc( sizeof( tVoomApp ) );

      /* If *app is still NULL, it means that malloc() failed.  */
      if( (tVoomApp *) NULL == *app ) {
	err = VOOM_E_MALLOC;
	break;
      }

      /* We set allocated to non-zero in case we error out      */
      /* somewhere past this point                              */

      allocated = 1;
    }

    memset( (*app), 0, sizeof( tVoomApp ) );

    (*app)->argc = argc;
    (*app)->argv = argv;

#ifdef WORDS_BIGENDIAN
    (*app)->fromConfig = VOOM_T_ENDBIG;
#else
    (*app)->fromConfig = VOOM_T_ENDLITTLE;
#endif

    word_test.t_word = 0x01234567;

    if( 0x01 == word_test.t_array[0] ) {
      (*app)->fromTest = VOOM_T_ENDBIG;
    } else {
      (*app)->fromTest = VOOM_T_ENDLITTLE;
    }

    (*app)->charsize     = sizeof( unsigned char );
    (*app)->shortsize    = sizeof( unsigned short );
    (*app)->intsize      = sizeof( unsigned int );
    (*app)->longsize     = sizeof( unsigned long );
    (*app)->longlongsize = sizeof( unsigned long long );
  } VOOM_END;

  /* If there's an error and we allocated something, free it */
  if( ( VOOM_E_NOERR != err ) || ( allocated != 0 ) ) {
    free( *app );
  } else {
    (*app)->allocated = allocated;
  }

  VOOM_EXIT;
}

tVoomErr voom_print( tVoomApp *app ) {
  VOOM_ENTER;
  static const char *endiannesses[] = {
    "unknown",
    "big",
    "little",
    NULL
  };

  VOOM_BEGIN {
    VOOM_NULLCHECK(app,tVoomApp*);

    if( app->fromConfig > VOOM_T_ENDLITTLE ) {
      app->fromConfig = VOOM_T_ENDUNKNOWN;
    }

    if( app->fromTest > VOOM_T_ENDLITTLE ) {
      app->fromTest = VOOM_T_ENDUNKNOWN;
    }

    printf( "config: %s\ntest:   %s\nchar:   %d\nshort:  %d\nint:    %d\nlong:   %d\nll:     %d\n", endiannesses[app->fromConfig], endiannesses[app->fromTest], app->charsize, app->shortsize, app->intsize, app->longsize, app->longlongsize );
  } VOOM_END;

  VOOM_EXIT;
}

tVoomErr voom_deinit( tVoomApp *app ) {
  VOOM_ENTER;

  VOOM_BEGIN {
    VOOM_NULLCHECK(app,tVoomApp*);
    if( 0 != app->allocated ) {
      free( app );
    }
  } VOOM_END;

  VOOM_EXIT;
}

tVoomErr voom_error( tVoomApp *app, tVoomErr err ) {

  static const char *errors[] = {
    "No",
    "Usage",
    "Memory Allocation",
    "File",
    "Null Parameter",
    "Unimplemented Feature",
    "Unknown",
    NULL
  };
  uint32_t internal_err;

  internal_err = (uint32_t) err;

  if( internal_err >= VOOM_E_MAX ) {
    internal_err = VOOM_E_UNKNOWN;
  }

  printf("%s Error\n", errors[ internal_err ] );

  switch( err ) {
  case VOOM_E_USAGE:
    voom_usage( app );
    break;
  case VOOM_E_FILE:
    voom_file();
    break;
  }

  return( VOOM_E_NOERR );
}

static void voom_usage( tVoomApp *app ) {
  printf("you should not see this usage message.\n");
}

static void voom_file( void ) {
  perror("voom");
}
